package com.etone.smartAudit.service;

import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.etone.smartAudit.config.CustomSecurity;
import com.etone.smartAudit.domain.Admin;
import com.etone.smartAudit.domain.AdminRole;
import com.etone.smartAudit.dto.AdminPageDTO;
import com.etone.smartAudit.dto.LoginDTO;
import com.etone.smartAudit.dto.PageDTO;
import com.etone.smartAudit.dto.admin.AdminDTO;
import com.etone.smartAudit.dto.admin.FindAdminDTO;
import com.etone.smartAudit.dto.admin.PasswordDTO;
import com.etone.smartAudit.dto.egcc.VerifyTokenDTO;
import com.etone.smartAudit.dto.egcc.VerifyUserVo;
import com.etone.smartAudit.error.CustomParameterizedException;
import com.etone.smartAudit.filter.TokenFilter;
import com.etone.smartAudit.mapper.AdminMapper;
import com.etone.smartAudit.mapper.ServiceExpertMapper;
import com.etone.smartAudit.mapstruct.AdminMapstruct;
import com.etone.smartAudit.security.jwt.TokenProvider;
import com.etone.smartAudit.vo.LoginVO;
import com.etone.smartAudit.vo.PUumUserinfoVO;
import com.etone.smartAudit.vo.PagerVO;
import com.etone.smartAudit.vo.admin.AdminDetailVO;
import com.etone.smartAudit.vo.admin.AdminListVO;
import com.etone.smartAudit.vo.admin.AdminSimpleVO;
import com.etone.smartAudit.vo.serviceExpert.ServiceExpertBaseVO;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import liquibase.pro.packaged.U;
import lombok.extern.slf4j.Slf4j;
import net.gmcc.portal.types.UIPService.AuthResult;
import net.gmcc.portal.types.UIPService.UserInfo;
import net.gmcc.portal.wsdl.UIPService.UIPServiceIFProxy;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.zalando.problem.Status;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import java.rmi.RemoteException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @author: sovy
 * @date: 2020-06-03 14:44:51
 * @description:
 */
@Service
@Slf4j
public class AdminService {

    @Autowired
    private AdminMapper adminMapper;

    @Autowired
    private AdminMapstruct adminMapstruct;

    @Autowired
    private AuthenticationManager authenticationManager;

    @Autowired
    private TokenProvider tokenProvider;

    @Autowired
    private AuthService authService;

    @Autowired
    private ServiceExpertMapper serviceExpertMapper;

    @Value("${gmcc.portal.system-id}")
    private String portalSystemId;

    @Value("${gmcc.portal.system-account}")
    private String portalSystemAccount;

    @Value("${gmcc.portal.system-pwd}")
    private String portalSystemPwd;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Value("${jwt.expiration:1}")
    private Long adminTokenExpirationTime;

    @Autowired
    private PUumUserinfoService uumUserinfoService;


    @Value("${portal.departName:'内审'}")
    private String orgDepartMentName;


    @Autowired
    private AdminRoleService adminRoleService;
    @Autowired
    private EGCCMService egccmService;

    /**
     * 条件查询
     *
     * @param keys
     * @param nickName
     * @param roleId
     * @param roleCodes
     * @param startTime
     * @param endTime
     * @param page
     * @param pageSize
     * @return
     */
    public PagerVO<AdminListVO> list(String keys, String nickName, Integer roleId, List<String> roleCodes, Date startTime, Date endTime, Integer page, Integer pageSize) {

        Page<AdminListVO> pageInfo = PageHelper
                .startPage(page, pageSize).setOrderBy("intId desc")
                .doSelectPage(() -> adminMapper.findList(
                        FindAdminDTO
                                .builder()
                                .roleCodes(roleCodes)
                                .nickName(nickName)
                                .keys(keys)
                                .roleId(roleId)
                                .startTime(startTime)
                                .endTime(endTime)
                                .build()
                ));

        return PagerVO.of(pageInfo);
    }

    /**
     * 查找基本信息列表
     *
     * @param admin
     * @param keys
     * @param permissionTypes
     * @param roleIds
     * @param serviceExpertIds
     * @param page
     * @param pageSize
     * @return
     */
    public PagerVO<AdminSimpleVO> listSimple(Admin admin, String keys, List<String> permissionTypes, List<Integer> roleIds, List<Integer> serviceExpertIds, int page, int pageSize) {
        Page<AdminSimpleVO> pageInfo = PageHelper.startPage(page, pageSize)
                .doSelectPage(() -> adminMapper.findListSimple(keys, permissionTypes, roleIds, serviceExpertIds));
        return PagerVO.of(pageInfo);
    }

    /**
     * 获取详情
     *
     * @param id
     * @return
     */
    public Admin get(Integer id) {
        Admin admin = adminMapper.selectById(id);
        if (admin != null) {
            return admin;
        }
        throw new CustomParameterizedException("该用户不存在");
    }

    /**
     * 获取返回详情
     *
     * @param id
     * @return
     */
    public AdminDetailVO getAdminVO(Integer id) {
        Admin admin = get(id);
        AdminDetailVO adminDetailVO = adminMapstruct.getAdminDetailVO(admin);
        List<ServiceExpertBaseVO> serviceExpertBaseVOS = serviceExpertMapper.findListSimpleByAdminId(id);
        adminDetailVO.setServiceExperts(serviceExpertBaseVOS);
        return adminDetailVO;
    }


    /**
     * 判断用户是否存在
     *
     * @param account
     */
    public Boolean accountExists(String account) {
        Admin admin = adminMapper.findByAccount(account);
        return admin != null;
    }

    /**
     * 增加|编辑
     *
     * @param adminDTO
     * @param id
     * @param createAdmin
     */
    @Transactional(rollbackFor = Exception.class)
    public void save(AdminDTO adminDTO, Integer id, Admin createAdmin) {

        Admin admin;
        if (id != null && id > 0) {
            admin = get(id);
            if (!admin.getAccount().equals(adminDTO.getAccount()) && accountExists(adminDTO.getAccount())) {
                throw new CustomParameterizedException("用户名已存在");
            }
        } else {
            if (accountExists(adminDTO.getAccount())) {
                throw new CustomParameterizedException("用户名已存在");
            }
            admin = Admin
                    .builder()
                    .createTime(new Date())
                    .createAdminId(createAdmin.getId())
                    .build();
        }
        adminMapstruct.copyToAdmin(admin, adminDTO);
        if (admin.getId() == null) {
            adminMapper.insert(admin);
        } else {
            adminMapper.updateById(admin);
        }

        //修改职位
        if (!CollectionUtils.isEmpty(adminDTO.getServiceExpertIds())) {
            updateServiceExpert(admin.getId(), adminDTO.getServiceExpertIds());
        }

    }


    /**
     * 修改职位
     *
     * @param adminId
     * @param serviceExpertIds
     */
    public void updateServiceExpert(Integer adminId, List<Integer> serviceExpertIds) {
        //删除专家
        adminMapper.deleteServiceExpertByAdmin(adminId);

        //批量新增专家
        adminMapper.batchInsertExpert(adminId, serviceExpertIds);
    }

    /**
     * 删除管理员
     *
     * @param id
     * @param loginAdmin
     */
    public void delete(Integer id, Admin loginAdmin) {
        if (id.intValue() == loginAdmin.getId().intValue()) {
            throw new CustomParameterizedException("无法删除自己");
        }
        int count = adminMapper.deleteById(id);
        if (count == 0) {
            throw new CustomParameterizedException("删除失败");
        }
    }

    /**
     * 批量删除管理员
     *
     * @param ids
     * @param loginAdmin
     */
    @Transactional(rollbackFor = Exception.class)
    public void delete(List<Integer> ids, Admin loginAdmin) {
        if (ids.contains(loginAdmin.getId())) {
            throw new CustomParameterizedException("无法删除自己");
        }
        int deleteCount = adminMapper.deleteBatchIds(ids);
        if (deleteCount == 0) {
            throw new CustomParameterizedException("删除失败");
        }
    }

    /**
     * 登陆
     *
     * @param loginDTO
     * @param checkCode 是否校验验证码
     * @return
     */
    public LoginVO login(LoginDTO loginDTO, boolean checkCode) {
        //校验验证码
        String verifyCode = authService.getVerifyCode(null, null, loginDTO.getUuid(), null);
        if (checkCode) {
            //删除校验码缓存
            authService.deleteVerifyCode(loginDTO.getUuid());
        }
        if (checkCode && !"string".equals(loginDTO.getCode())) {
            if (!verifyCode.toLowerCase().equals(loginDTO.getCode().toLowerCase())) {
                throw new CustomParameterizedException("验证码错误");
            }
        }
        UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(loginDTO.getAccount(), loginDTO.getPassword());
        Authentication authentication;
        try {
            // 通过 AuthenticationManager（默认实现为ProviderManager）的authenticate方法验证 Authentication 对象
            authentication = authenticationManager.authenticate(authenticationToken);
        } catch (Exception e) {
            e.printStackTrace();
            throw new CustomParameterizedException("登录失败，请检查您的用户名或密码是否填写正确。");
        }
        SecurityContextHolder.getContext().setAuthentication(authentication);
        List<SimpleGrantedAuthority> simpleGrantedAuthorityList = (List<SimpleGrantedAuthority>) authentication.getAuthorities();
        List<String> roles = simpleGrantedAuthorityList.stream().map(simpleGrantedAuthority -> simpleGrantedAuthority.getAuthority()).collect(Collectors.toList());
        String token = "Bearer " + tokenProvider.createToken(authentication, false);

        Admin admin = adminMapper.findByAccount(loginDTO.getAccount());
        stringRedisTemplate.opsForValue().set(TokenFilter.REDIS_TOKEN_KEY_PREFIX + admin.getAccount(), token, adminTokenExpirationTime, TimeUnit.SECONDS);
        String code = null;
        if (admin.getRole() != null) {
            code = admin.getRole().getCode();
        }

        return LoginVO.builder().token(token).nickName(admin.getNickName()).isSupper(admin.isAdmin()).id(admin.getId()).roles(roles).code(code).build();
    }

    /**
     * 移动单点登录
     *
     * @param request
     * @return
     */
    public LoginVO gmccPortalLogin(HttpServletRequest request) {
        log.info("======>portal单点登录");
        Cookie[] cookies = request.getCookies();
        String gmccToken = null;
        for (Cookie cookie : cookies) {
            if ("iPlanetDirectoryPro".equals(cookie.getName())) {
                gmccToken = cookie.getValue();
                break;
            }
        }
        log.info("======>单点登录token:{}", gmccToken);
        Admin admin = null;
        if (gmccToken == null) {
            log.info("======>单点登录无效token");
            throw new CustomParameterizedException("无效token", Status.FORBIDDEN);
        }
        if ("gmccTokenAdminTest".equals(gmccToken)) {
            admin = adminMapper.findByAccount("admin");
        } else {
            UIPServiceIFProxy proxy = new UIPServiceIFProxy();
            try {
                //参数1 当前登录PORTAL用户的令牌,该值可以从request.getCookie()上遍历到，该值的名字为：iPlanetDirectoryPro
                //参数2 为portal分配的系统ID，该值需要提接入申请单给PORTAL进行备案
                log.info("======>portalSystemId：{}", portalSystemId);
                AuthResult result = proxy.getUIPServiceIF().validateToken(gmccToken, portalSystemId);//验证portal令牌
                log.info("======>单点登录校验token结果:{}", JSON.toJSONString(result));
                //令牌验证成功
                if (result.isAuthResult()) {
                    String queryUser = result.getAccount();
                    //获取用户详细信息
                    //UserInfo:{"address":"广州市天河区兴盛路12号之二隽峰苑A8-2301","cmccaccount":"hujungang@gd.cmcc","company":"省公司","companyid":"72D67DB594164E00954CE7D2C74124A9","department":"内审部","departmentid":"D82ABF063987409C855B32ED5246E2B6","email":"hujungang@gd.chinamobile.com","employeeNum":"0121021583","ext1":"100090","fullName":"胡俊刚","jobTitle":"000001","mobilePhone":"13902220092","orderid":"100090","ouid":4660,"region":"gmcc","uid":"hujungang","workPhone":""}
                    UserInfo info = proxy.getUIPServiceIF().getUserInfoByUserID(queryUser, portalSystemAccount, portalSystemPwd);
                    log.info("======>单点登录用户详细信息:{}", JSON.toJSONString(info));
                    admin = adminMapper.findByAccount(queryUser);
                    if (admin == null) {
                        //添加进系统账号
                        admin = addPortalUserToAdmin(info);
                        log.info("======>账号不存在,已进行添加");
//                        throw new CustomParameterizedException("账号不存在");
                    }
                } else {
//                    throw new CustomParameterizedException(result.getAuthMsg());
                    throw new CustomParameterizedException("Token校验失败，请尝试关闭当前页面重新进入");
                }
            } catch (RemoteException e) {
                e.printStackTrace();
                throw new CustomParameterizedException(e.getMessage());
            }
        }
        return login(LoginDTO.builder().account(admin.getAccount()).password(admin.getPassword()).build(), false);
    }

    /***
     * 添加portal用户到admin
     * @param userInfo
     */
    private Admin addPortalUserToAdmin(UserInfo userInfo) {

        //获取portal账号信息
        String department = userInfo.getDepartment();
        //判断是不是内审部的员工，如果是内审部则给予管理员权限。
        List<String> adminDepart = Arrays.asList(orgDepartMentName.split(","));

        //说明是管理员权限
        AdminRole adminRole;
        if (adminDepart.contains(department)) {
            adminRole = adminRoleService.getRoleByCode("R_ADMIN");
        } else {
            adminRole = adminRoleService.getRoleByCode("R_PORTAL_OTHER");
        }

        Admin admin = Admin.builder()
                .account(userInfo.getUid())
//                .companyId()
                .companyName(userInfo.getCompany())
                .createAdminId(111111111)
                .createTime(new Date())
                .email(userInfo.getEmail())
                .isSuper(false)
                .nickName(userInfo.getFullName())
                .password("efwefwefer")
                .email(userInfo.getEmail())
                .roleId(adminRole.getId())
                .tel(userInfo.getMobilePhone())
                .build();
        adminMapper.insert(admin);
        admin.setRole(adminRole);
        return admin;
    }

    /**
     * 退出登录
     *
     * @param admin
     */
    public void logout(Admin admin) {
        String key = TokenFilter.REDIS_TOKEN_KEY_PREFIX + admin.getAccount();
        String authKey = tokenProvider.getPermiKey(admin.getAccount());
        if (stringRedisTemplate.hasKey(key)) {
            stringRedisTemplate.delete(key);
        }

        if (stringRedisTemplate.hasKey(authKey)) {
            stringRedisTemplate.delete(authKey);
        }
    }

    /**
     * 修改密码
     *
     * @param admin
     * @param passwordDTO
     */
    public void updatePwd(Admin admin, PasswordDTO passwordDTO) {
        Admin curAdmin = adminMapper.findByAccount(admin.getAccount());
        if (!curAdmin.getPassword().equals(passwordDTO.getOldPassword())) {
            throw new CustomParameterizedException("密码错误");
        }
        adminMapper.updatePwd(admin.getAccount(), passwordDTO.getPassword());
    }

    /***
     * 根据id获取用户列表
     * @param ids
     * @return
     */
    public List<Admin> getAdminsByIds(List<Integer> ids) {
        if (CollectionUtils.isEmpty(ids)) {
            return new ArrayList<>();
        }
        LambdaQueryWrapper<Admin> query = new LambdaQueryWrapper<>();
        query.in(Admin::getId, ids);
        return adminMapper.selectList(query);
    }

    /***
     * E掌通单点登录
     * @param dto
     * @return
     */
    public LoginVO getEztLogin(VerifyTokenDTO dto) {
        VerifyUserVo result = egccmService.validateLoginToken(dto);
        if (result == null) {
            throw new CustomParameterizedException("E掌通登录失败");
        }
        // TODO  获取portal用户执行登录
        Admin admin = adminMapper.findByAccount(result.getUid());
        if (admin == null) {
            //添加进系统账号
            UserInfo info = new UserInfo();
            info.setUid(result.getUid());
            info.setMobilePhone(result.getMobile());
            info.setDepartment(result.getRegion());
            admin = addPortalUserToAdmin(info);
            log.info("======>账号不存在,已进行添加");
        }
        return login(LoginDTO.builder().account(admin.getAccount()).password(admin.getPassword()).build(), false);
    }

    /***
     * 获取系统人员
     * @param pageDTO
     * @return
     */
    public PagerVO<PUumUserinfoVO> getCompanyUsers(AdminPageDTO pageDTO) {
        Page<PUumUserinfoVO> pageInfo = PageHelper.startPage(pageDTO.getPage(), pageDTO.getPageSize())
                .doSelectPage(() -> adminMapper.findUserSimple(pageDTO));

        return PagerVO.of(pageInfo);
    }
}